package 数组题目.前缀和与差分;

import java.util.HashMap;

//连续数组
//https://leetcode.cn/problems/contiguous-array/
//给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组，并返回该子数组的长度。
class 连续数组 {
    //将0转换为-1,从而进行前缀和操作，如果出现过一次值相同的两个值，则其间距为答案长度
    public int findMaxLength(int[] nums) {
        // 0 -1 0 1 2 3 4 3 2 1
        // 0 -1 0 1 2 3 4 3 2 1 0 -1 0
        int n = nums.length;
        int[] preSum = new int[n + 1];
        preSum[0] = 0;
        // 计算 nums 的前缀和
        for (int i = 0; i < n; i++) {
            preSum[i + 1] = preSum[i] + (nums[i] == 0 ? -1 : 1);
        }
        // 前缀和到索引的映射，方便快速查找所需的前缀和
        HashMap<Integer, Integer> valToIndex = new HashMap<>();
        int res = 0;
        for (int i = 0; i < preSum.length; i++) {
            // 如果这个前缀和还没有对应的索引，说明这个前缀和第一次出现，记录下来
            if (!valToIndex.containsKey(preSum[i])) {
                valToIndex.put(preSum[i], i);
            } else {
                // 这个前缀和已经出现过了，则找到一个和为 0 的子数组
                res = Math.max(res, i - valToIndex.get(preSum[i]));
            }
            // 因为题目想找长度最大的子数组，所以前缀和索引应尽可能小
        }
        return res;
    }

    public static void main(String[] args) {
        System.out.println(new 连续数组().findMaxLength(new int[]{0, 1, 1, 1, 1, 1, 0, 0, 0}));
        System.out.println(new 连续数组().findMaxLength(new int[]{0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1}));
    }
}
